package com.coalmine.api.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.coalmine.api.domain.ApiConfig;
import com.coalmine.api.domain.ApiToken;
import com.coalmine.api.enums.EApiPermission;
import com.coalmine.api.service.IApiConfigService;
import com.coalmine.api.service.IApiTokenService;
import com.coalmine.common.constant.HttpStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

/**
 * 权限过滤器
 * @author 尚郑
 *
 */
@Slf4j
@Component
public class ApiAuthFilter implements Filter {

    @Autowired
    private IApiConfigService apiConfigService;

    @Autowired
    private IApiTokenService tokenService;
 

    @Value("${datamanage.api.context}")
    String context;
    @Value("${datamanage.api.result}")
    String apiResult;
    @Value("${datamanage.api.set}")
    String apiResultSet;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException {
        JSONObject json = new JSONObject();
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        // 检查请求地址是否是api请求
        String url = request.getRequestURI();
        try {
            if (url.contains(context)) {
                // 查询请求地址是否存在 去除/dm字符串
                url = url.substring(context.length() + 2);
                // 查询请求地址是否存在 去除/query字符串
                if (url.contains(apiResult)) {
                    url = url.substring(apiResult.length() + 1);
                }
                if (url.contains(apiResultSet)) {
                    url = url.substring(apiResultSet.length() + 1);
                }
                ApiConfig config = apiConfigService.getConfig(url);
                if (config == null) {
                    json.put("code", HttpStatus.NOT_FOUND);
                    json.put("msg", "资源未找到！！！");
                    setResponse(response, json.toString());
                    return;
                }
                // 如果是私有接口，校验权限
                if (config.getPrevilege() == EApiPermission.PRIVATE.getCode()) {
                    String tokenStr = request.getParameter("token");
                    if (StrUtil.isBlank(tokenStr)) {
                        tokenStr = request.getHeader("token");
                    }
                    if (StrUtil.isBlank(tokenStr)) {
                        json.put("code", HttpStatus.UNAUTHORIZED);
                        json.put("msg", "无token,请联系管理员！！！");
                        setResponse(response, json.toString());
                        return;
                    } else {
                        ApiToken token = tokenService.getToken(tokenStr);
                        if (token == null) {
                            json.put("code", HttpStatus.UNAUTHORIZED);
                            json.put("msg", "权限不足,请联系管理员！！！");
                            setResponse(response, json.toString());
                            return;
                        } else {
                            if (token.getExpire() != null && token.getExpire() < System.currentTimeMillis()) {
                                json.put("code", HttpStatus.UNAUTHORIZED);
                                json.put("msg", "Token已过期,请重新获取！！！");
                                setResponse(response, json.toString());
                                return;
                            } else {
                                // log.info("token存在且有效");
                                List<String> authGroups = tokenService.getAuthGroups(token.getId());
                                if (checkAuth(authGroups, config.getGroupId()) && checkApiPerm(config, tokenStr)) {

                                } else {
                                    json.put("code", HttpStatus.UNAUTHORIZED);
                                    json.put("msg", "权限不足,请联系管理员！！！");
                                    setResponse(response, json.toString());
                                    return;
                                }
                            }
                        }
                    }
                }
            }
            filterChain.doFilter(servletRequest, servletResponse);
        } catch (Exception e) {
            json.put("code", HttpStatus.ERROR);
            json.put("msg", "系统异常....");
            setResponse(response, json.toString());
            return;
        }

    }

    @Override
    public void destroy() {

    }

    private boolean checkApiPerm(ApiConfig config, String token) {
        if (EApiPermission.PUBLIC.getCode() == config.getPrevilege()) {
            return true;
        }
        if (EApiPermission.PRIVATE.getCode() == config.getPrevilege()) {
            ApiToken apiToken = tokenService.getToken(token);
            if (com.coalmine.common.utils.StringUtils.isNull(apiToken)) {
                return false;
            }
            return true;
        }
        // TODO 其他类型新增判断
        return true;
    }


    public boolean checkAuth(List<String> authGroups, String group) {
        for (String authGroup : authGroups) {
            if (authGroup.equals(group)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 设置返回错误
     * @param response
     * @param msg
     * @return
     */
    public void setResponse(HttpServletResponse response, String msg) {
        //设置编码格式
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter pw = null;
        try {
            pw = response.getWriter();
            pw.write(msg);
        } catch (IOException e) {
            log.error("响应失败！");
        } finally {
            pw.flush();
            pw.close();
        }
    }
}